package com.hanxiaozhang.result;


import com.hanxiaozhang.exception.BusinessException;
import com.hanxiaozhang.exception.BusinessExceptionEnum;
import com.hanxiaozhang.exception.ResultCode;
import com.hanxiaozhang.util.RequestContextUtil;
import com.hanxiaozhang.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.http.HttpStatus;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 功能描述: <br>
 * 〈正常返回结果〉
 *
 * @Author:hanxinghua
 * @Date: 2020/7/21
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Result<T> implements Serializable {

	private static final long serialVersionUID = 874200365941306385L;

	/**
	 * 编码
	 */
	private Integer code;

	/**
	 * 信息
	 */
	private String msg;

	/**
	 * 时间戳
	 */
	private long time;


	/**
	 * 返回数据
	 */
	private T data;

	public Result(T data) {
		this.code = ResultCode.SUCCESS.code();
		this.msg = ResultCode.SUCCESS.message();
		this.data = data;
	}

	public Result(ResultCode resultCode, T data) {
		this.code = resultCode.code();
		this.msg = resultCode.message();
		this.data = data;
	}

	public static Result success() {
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		return result;
	}

	public static <T> Result success(T data) {
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		result.setData(data);
		return result;
	}

	public static Result error(ResultCode resultCode) {
		Result result = new Result();
		result.setResultCode(resultCode);
		return result;
	}

	public static <T> Result error(ResultCode resultCode, T data) {
		Result result = new Result();
		result.setResultCode(resultCode);
		result.setData(data);
		return result;
	}

	public static Result error(BusinessException e) {
		BusinessExceptionEnum ee = BusinessExceptionEnum.getByEClass(e.getClass());
		if (ee != null) {
			return Result.error(ee.getResultCode(), e, ee.getHttpStatus(), e.getData());
		}

		Result result = Result.error(e.getResultCode() == null ? ResultCode.NO_DEFINITION : e.getResultCode(), e, HttpStatus.OK, e.getData());

		if (StringUtil.isNotBlank(e.getMessage())) {
			result.setMsg(e.getMessage());
		}

		return result;
	}

	public static Result error(ResultCode resultCode, Throwable e, HttpStatus httpStatus) {

		Map<String, Object> map =new LinkedHashMap<>(8);
		map.put("status",httpStatus.value());
		map.put("error",httpStatus.getReasonPhrase());
		map.put("exception",e.getClass().getName());
		map.put("exceptionMsg",e.getMessage());
		map.put("cause",e.getCause()==null?null:e.getCause().toString());
		map.put("path",RequestContextUtil.getRequest()==null?null:RequestContextUtil.getRequest().getRequestURI());

		Result<Map<String, Object>> result = new Result<>();
		result.setCode(resultCode.code())
				.setMsg(resultCode.message())
				.setData(map);
		return result;
	}

	public static <T> Result error(ResultCode resultCode, Throwable e, HttpStatus httpStatus, T errorMsg) {
		Result result = Result.error(resultCode, e, httpStatus);
		Map<String, Object> map = (Map<String, Object>) result.getData();
		map.put("exceptionMsg",errorMsg);
		return result;
	}


	private void setResultCode(ResultCode code) {
		this.code = code.code();
		this.msg = code.message();
	}

	public long getTime() {
		return time==0?System.currentTimeMillis():time;
	}


}
